using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline.Processors;
using System.ComponentModel;

namespace Luminal.Pipeline
{
    [ContentProcessor(DisplayName = "OpenCL Processor - Luminal")]
    public class LuminalProcessor : ContentProcessor<string, string>
    {
        DeviceType deviceType = DeviceType.Default;

        [Description("Defines which type of device to attempt compiling against.")]
        [DefaultValue(typeof(DeviceType), "Default")]
        public DeviceType DeviceType
        {
            get { return deviceType; }
            set { deviceType = value; }
        }

        public override string Process(string input, ContentProcessorContext context)
        {
            Context clContext = new Context(PlatformIdentifier.Default, deviceType);
            Program program = Program.FromSource(clContext, input);
            
            string[] buildLogs = null;
            try
            {
                if (!program.Build(clContext.Devices, null, out buildLogs))
                {
                    foreach (string log in buildLogs)
                        context.Logger.LogWarning(null, null, "OpenCL Build Log:\n{0}", log);

                    throw new Exception("Could not build program.");
                }
            }
            catch (LuminalException e)
            {
                if (buildLogs != null)
                {
                    foreach (string log in buildLogs)
                        context.Logger.LogWarning(null, null, "OpenCL Build Log:\n{0}", log);
                }

                throw new Exception("An exception occured attempting to build the program:\n" + e.Message);
            }
            finally
            {
                clContext.Dispose();

                if (program != null)
                    program.Dispose();
            }

            return input;
        }
    }
}